home *** CD-ROM | disk | FTP | other *** search
/ PC/CD Gamer UK 120 / CD Gamer Issue 120 (March 2003) (Disc 2).ISO / mods / Q2_Codered / codeRED1_0.exe / Data1.cab / snd_mem.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-13  |  7.0 KB  |  360 lines

  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // snd_mem.c: sound caching
  21.  
  22. #include "client.h"
  23. #include "snd_loc.h"
  24.  
  25. int            cache_full_cycle;
  26.  
  27. byte *S_Alloc (int size);
  28.  
  29. /*
  30. ================
  31. ResampleSfx
  32. ================
  33. */
  34. void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data)
  35. {
  36.     int        outcount;
  37.     int        srcsample;
  38.     float    stepscale;
  39.     int        i;
  40.     int        sample, samplefrac, fracstep;
  41.     sfxcache_t    *sc;
  42.     
  43.     sc = sfx->cache;
  44.     if (!sc)
  45.         return;
  46.  
  47.     stepscale = (float)inrate / dma.speed;    // this is usually 0.5, 1, or 2
  48.  
  49.     outcount = sc->length / stepscale;
  50.     sc->length = outcount;
  51.     if (sc->loopstart != -1)
  52.         sc->loopstart = sc->loopstart / stepscale;
  53.  
  54.     sc->speed = dma.speed;
  55.     if (s_loadas8bit->value)
  56.         sc->width = 1;
  57.     else
  58.         sc->width = inwidth;
  59.     sc->stereo = 0;
  60.  
  61. // resample / decimate to the current source rate
  62.  
  63.     if (stepscale == 1 && inwidth == 1 && sc->width == 1)
  64.     {
  65. // fast special case
  66.         for (i=0 ; i<outcount ; i++)
  67.             ((signed char *)sc->data)[i]
  68.             = (int)( (unsigned char)(data[i]) - 128);
  69.     }
  70.     else
  71.     {
  72. // general case
  73.         samplefrac = 0;
  74.         fracstep = stepscale*256;
  75.         for (i=0 ; i<outcount ; i++)
  76.         {
  77.             srcsample = samplefrac >> 8;
  78.             samplefrac += fracstep;
  79.             if (inwidth == 2)
  80.                 sample = LittleShort ( ((short *)data)[srcsample] );
  81.             else
  82.                 sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
  83.             if (sc->width == 2)
  84.                 ((short *)sc->data)[i] = sample;
  85.             else
  86.                 ((signed char *)sc->data)[i] = sample >> 8;
  87.         }
  88.     }
  89. }
  90.  
  91. //=============================================================================
  92.  
  93. /*
  94. ==============
  95. S_LoadSound
  96. ==============
  97. */
  98. sfxcache_t *S_LoadSound (sfx_t *s)
  99. {
  100.     char    namebuffer[MAX_QPATH];
  101.     byte    *data;
  102.     wavinfo_t    info;
  103.     int        len;
  104.     float    stepscale;
  105.     sfxcache_t    *sc;
  106.     int        size;
  107.     char    *name;
  108.  
  109.     if (s->name[0] == '*')
  110.         return NULL;
  111.  
  112. // see if still in memory
  113.     sc = s->cache;
  114.     if (sc)
  115.         return sc;
  116.  
  117. //Com_Printf ("S_LoadSound: %x\n", (int)stackbuf);
  118. // load it in
  119.     if (s->truename)
  120.         name = s->truename;
  121.     else
  122.         name = s->name;
  123.  
  124.     if (name[0] == '#')
  125.         strcpy(namebuffer, &name[1]);
  126.     else
  127.         Com_sprintf (namebuffer, sizeof(namebuffer), "sound/%s", name);
  128.  
  129. //    Com_Printf ("loading %s\n",namebuffer);
  130.  
  131.     size = FS_LoadFile (namebuffer, (void **)&data);
  132.  
  133.     if (!data)
  134.     {
  135.         Com_DPrintf ("Couldn't load %s\n", namebuffer);
  136.         return NULL;
  137.     }
  138.  
  139.     info = GetWavinfo (s->name, data, size);
  140.     if (info.channels != 1)
  141.     {
  142.         Com_Printf ("%s is a stereo sample\n",s->name);
  143.         FS_FreeFile (data);
  144.         return NULL;
  145.     }
  146.  
  147.     stepscale = (float)info.rate / dma.speed;    
  148.     len = info.samples / stepscale;
  149.  
  150.     len = len * info.width * info.channels;
  151.  
  152.     sc = s->cache = Z_Malloc (len + sizeof(sfxcache_t));
  153.     if (!sc)
  154.     {
  155.         FS_FreeFile (data);
  156.         return NULL;
  157.     }
  158.     
  159.     sc->length = info.samples;
  160.     sc->loopstart = info.loopstart;
  161.     sc->speed = info.rate;
  162.     sc->width = info.width;
  163.     sc->stereo = info.channels;
  164.  
  165.     ResampleSfx (s, sc->speed, sc->width, data + info.dataofs);
  166.  
  167.     FS_FreeFile (data);
  168.  
  169.     return sc;
  170. }
  171.  
  172.  
  173.  
  174. /*
  175. ===============================================================================
  176.  
  177. WAV loading
  178.  
  179. ===============================================================================
  180. */
  181.  
  182.  
  183. byte    *data_p;
  184. byte     *iff_end;
  185. byte     *last_chunk;
  186. byte     *iff_data;
  187. int     iff_chunk_len;
  188.  
  189.  
  190. short GetLittleShort(void)
  191. {
  192.     short val = 0;
  193.     val = *data_p;
  194.     val = val + (*(data_p+1)<<8);
  195.     data_p += 2;
  196.     return val;
  197. }
  198.  
  199. int GetLittleLong(void)
  200. {
  201.     int val = 0;
  202.     val = *data_p;
  203.     val = val + (*(data_p+1)<<8);
  204.     val = val + (*(data_p+2)<<16);
  205.     val = val + (*(data_p+3)<<24);
  206.     data_p += 4;
  207.     return val;
  208. }
  209.  
  210. void FindNextChunk(char *name)
  211. {
  212.     while (1)
  213.     {
  214.         data_p=last_chunk;
  215.  
  216.         if (data_p >= iff_end)
  217.         {    // didn't find the chunk
  218.             data_p = NULL;
  219.             return;
  220.         }
  221.         
  222.         data_p += 4;
  223.         iff_chunk_len = GetLittleLong();
  224.         if (iff_chunk_len < 0)
  225.         {
  226.             data_p = NULL;
  227.             return;
  228.         }
  229. //        if (iff_chunk_len > 1024*1024)
  230. //            Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);
  231.         data_p -= 8;
  232.         last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
  233.         if (!strncmp(data_p, name, 4))
  234.             return;
  235.     }
  236. }
  237.  
  238. void FindChunk(char *name)
  239. {
  240.     last_chunk = iff_data;
  241.     FindNextChunk (name);
  242. }
  243.  
  244.  
  245. void DumpChunks(void)
  246. {
  247.     char    str[5];
  248.     
  249.     str[4] = 0;
  250.     data_p=iff_data;
  251.     do
  252.     {
  253.         memcpy (str, data_p, 4);
  254.         data_p += 4;
  255.         iff_chunk_len = GetLittleLong();
  256.         Com_Printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len);
  257.         data_p += (iff_chunk_len + 1) & ~1;
  258.     } while (data_p < iff_end);
  259. }
  260.  
  261. /*
  262. ============
  263. GetWavinfo
  264. ============
  265. */
  266. wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
  267. {
  268.     wavinfo_t    info;
  269.     int     i;
  270.     int     format;
  271.     int        samples;
  272.  
  273.     memset (&info, 0, sizeof(info));
  274.  
  275.     if (!wav)
  276.         return info;
  277.         
  278.     iff_data = wav;
  279.     iff_end = wav + wavlength;
  280.  
  281. // find "RIFF" chunk
  282.     FindChunk("RIFF");
  283.     if (!(data_p && !strncmp(data_p+8, "WAVE", 4)))
  284.     {
  285.         Com_Printf("Missing RIFF/WAVE chunks\n");
  286.         return info;
  287.     }
  288.  
  289. // get "fmt " chunk
  290.     iff_data = data_p + 12;
  291. // DumpChunks ();
  292.  
  293.     FindChunk("fmt ");
  294.     if (!data_p)
  295.     {
  296.         Com_Printf("Missing fmt chunk\n");
  297.         return info;
  298.     }
  299.     data_p += 8;
  300.     format = GetLittleShort();
  301.     if (format != 1)
  302.     {
  303.         Com_Printf("Microsoft PCM format only\n");
  304.         return info;
  305.     }
  306.  
  307.     info.channels = GetLittleShort();
  308.     info.rate = GetLittleLong();
  309.     data_p += 4+2;
  310.     info.width = GetLittleShort() / 8;
  311.  
  312. // get cue chunk
  313.     FindChunk("cue ");
  314.     if (data_p)
  315.     {
  316.         data_p += 32;
  317.         info.loopstart = GetLittleLong();
  318. //        Com_Printf("loopstart=%d\n", sfx->loopstart);
  319.  
  320.     // if the next chunk is a LIST chunk, look for a cue length marker
  321.         FindNextChunk ("LIST");
  322.         if (data_p)
  323.         {
  324.             if (!strncmp (data_p + 28, "mark", 4))
  325.             {    // this is not a proper parse, but it works with cooledit...
  326.                 data_p += 24;
  327.                 i = GetLittleLong ();    // samples in loop
  328.                 info.samples = info.loopstart + i;
  329. //                Com_Printf("looped length: %i\n", i);
  330.             }
  331.         }
  332.     }
  333.     else
  334.         info.loopstart = -1;
  335.  
  336. // find data chunk
  337.     FindChunk("data");
  338.     if (!data_p)
  339.     {
  340.         Com_Printf("Missing data chunk\n");
  341.         return info;
  342.     }
  343.  
  344.     data_p += 4;
  345.     samples = GetLittleLong () / info.width;
  346.  
  347.     if (info.samples)
  348.     {
  349.         if (samples < info.samples)
  350.             Com_Error (ERR_DROP, "Sound %s has a bad loop length", name);
  351.     }
  352.     else
  353.         info.samples = samples;
  354.  
  355.     info.dataofs = data_p - wav;
  356.     
  357.     return info;
  358. }
  359.  
  360.